package xyz.scootaloo.kami.server.service

import io.vertx.core.Future
import xyz.scootaloo.kami.server.model.SysTask
import xyz.scootaloo.kami.server.standard.SyncMark
import xyz.scootaloo.kami.server.service.impl.InternalCrontabServiceImpl

/**
 * 定时任务管理器
 *
 * @author flutterdash@qq.com
 * @since 2022/2/23 14:07
 */
interface CrontabService {

    fun submit(task: Crontab): Future<Unit>

    companion object {
        /**
         * 系统每100毫秒执行一次[Crontab]的任务,
         * [Crontab]有一个[Crontab.delay]属性, 这个属性代表执行此任务的间隔.
         *
         * 假设启动服务的当前时间为1000(毫秒), 某个任务需要每250毫秒执行一次, 那么会有如下流程:
         * 1000  服务启动, 记录这个任务被纳入管理的时间(lastExeTime) = 1000
         * 1100  检查 (currentTime - lastExeTime > delay)?
         * 1200  检查 (currentTime - lastExeTime > delay)?
         * 1300  检查 (currentTime - lastExeTime > delay)? 执行任务, 并更新 lastExeTime = 1300
         * 1400  检查 (currentTime - lastExeTime > delay)?
         * 1500  检查 (currentTime - lastExeTime > delay)?
         * 1500  检查 (currentTime - lastExeTime > delay)?
         * 1600  检查 (currentTime - lastExeTime > delay)? 执行任务, 并更新 lastExeTime = 1600
         * ... ...
         *
         * 以此可见, 任务执行的间隔并不准确,
         * 如果希望每此都能执行任务, 应该把delay属性设置为小于100
         */
        const val defDelay: Long = 100

        operator fun invoke(): CrontabService {
            return InternalCrontabServiceImpl
        }
    }

    interface Crontab {
        /**
         * 可以在[run]方法中修改这个属性, 当这个属性为false时, 当前任务会从全局任务中注销
         */
        var valid: Boolean

        /**
         * 执行任务的间隔(单位毫秒), 可以动态调整
         */
        var delay: Long

        /**
         * 任务名, 这个名称必须是唯一的
         */
        val name: String

        /**
         * 优先级, 数字越小优先级越高; 只能取1 - 9, 包括1和9
         */
        val order: Int

        /**
         * 定时执行的任务, 这个方法中的代码会同步执行
         */
        @SyncMark
        fun run()

        companion object {
            const val defOrder = 5
        }
    }

    interface DatabaseCrontabHandler {
        fun handle(dbTask: SysTask)

        companion object {
            const val UPLOAD_TASK = 1
        }
    }
}